<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>基于降低音量倍速功能的subliminal制作器</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }

        .container {
            background: rgba(255, 255, 255, 0.9);
            backdrop-filter: blur(10px);
            border-radius: 20px;
            box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
            width: 100%;
            max-width: 600px;
            padding: 40px;
            text-align: center;
        }

        h1 {
            color: #333;
            margin-bottom: 30px;
            font-size: 28px;
            font-weight: 600;
        }

        .upload-section {
            margin-bottom: 30px;
        }

        .file-upload {
            position: relative;
            display: inline-block;
            cursor: pointer;
            margin-bottom: 20px;
        }

        .file-upload-input {
            position: absolute;
            left: 0;
            top: 0;
            opacity: 0;
            width: 100%;
            height: 100%;
            cursor: pointer;
        }

        .file-upload-label {
            display: block;
            padding: 15px 30px;
            background: linear-gradient(45deg, #667eea, #764ba2);
            color: white;
            border-radius: 50px;
            font-weight: 600;
            transition: all 0.3s ease;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
        }

        .file-upload-label:hover {
            transform: translateY(-3px);
            box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
        }

        .file-name {
            margin-top: 10px;
            font-size: 14px;
            color: #666;
        }

        .control-group {
            margin-bottom: 25px;
            text-align: left;
        }

        .control-header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 10px;
        }

        label {
            font-weight: 600;
            color: #333;
        }

        .value-display {
            background: #f0f0f0;
            padding: 3px 10px;
            border-radius: 20px;
            font-size: 14px;
            color: #666;
        }

        input[type="range"] {
            width: 100%;
            height: 10px;
            -webkit-appearance: none;
            background: #ddd;
            border-radius: 5px;
            outline: none;
        }

        input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 22px;
            height: 22px;
            background: linear-gradient(45deg, #667eea, #764ba2);
            border-radius: 50%;
            cursor: pointer;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
        }

        .preview-section {
            margin-top: 30px;
        }

        audio {
            width: 100%;
            margin-top: 15px;
            outline: none;
        }

        .btn-group {
            display: flex;
            gap: 15px;
            margin-top: 25px;
        }

        button {
            flex: 1;
            padding: 15px;
            border: none;
            border-radius: 50px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
        }

        .process-btn {
            background: linear-gradient(45deg, #667eea, #764ba2);
            color: white;
        }

        .download-btn {
            background: linear-gradient(45deg, #4CAF50, #8BC34A);
            color: white;
            display: none;
        }

        button:hover {
            transform: translateY(-3px);
            box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
        }

        button:active {
            transform: translateY(0);
        }

        .disabled {
            opacity: 0.6;
            cursor: not-allowed;
        }

        .instructions {
            background: #e3f2fd;
            border-radius: 10px;
            padding: 20px;
            margin-top: 30px;
            text-align: left;
        }

        .instructions h3 {
            margin-bottom: 10px;
            color: #333;
        }

        .instructions ul {
            padding-left: 20px;
        }

        .instructions li {
            margin-bottom: 8px;
            color: #555;
        }

        .processing-indicator {
            margin-top: 15px;
            display: none;
        }

        .progress-bar {
            height: 10px;
            background: #e0e0e0;
            border-radius: 5px;
            overflow: hidden;
        }

        .progress {
            height: 100%;
            background: linear-gradient(45deg, #667eea, #764ba2);
            width: 0%;
            transition: width 0.3s;
        }

        @media (max-width: 600px) {
            .container {
                padding: 20px;
            }
            
            .btn-group {
                flex-direction: column;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>潜意识音频制作器</h1>
        
        <div class="upload-section">
            <div class="file-upload">
                <input type="file" id="audioFile" class="file-upload-input" accept="audio/*">
                <label for="audioFile" class="file-upload-label">选择音频文件</label>
            </div>
            <div class="file-name" id="fileName">未选择文件</div>
        </div>

        <div class="control-group">
            <div class="control-header">
                <label for="volume">音量控制</label>
                <span class="value-display"><span id="volumeValue">100</span>%</span>
            </div>
            <input type="range" id="volume" min="0" max="100" value="100">
        </div>

        <div class="control-group">
            <div class="control-header">
                <label for="speed">播放速度</label>
                <span class="value-display"><span id="speedValue">1.0</span>x</span>
            </div>
            <input type="range" id="speed" min="0.5" max="10" step="0.1" value="1">
        </div>

        <div class="preview-section">
            <label>音频预览</label>
            <audio id="audioPreview" controls></audio>
        </div>

        <div class="processing-indicator" id="processingIndicator">
            <div>正在处理音频...</div>
            <div class="progress-bar">
                <div class="progress" id="progressBar"></div>
            </div>
        </div>

        <div class="btn-group">
            <button id="processBtn" class="process-btn">处理音频</button>
            <button id="downloadBtn" class="download-btn">下载处理后音频</button>
        </div>

        <div class="instructions">
            <h3>使用说明:</h3>
            <ul>
                <li>上传您想要处理的音频文件</li>
                <li>调整音量滑块来降低音频音量</li>
                <li>调整速度滑块来改变播放速度</li>
                <li>点击"处理音频"按钮应用设置</li>
                <li>处理完成后可预览并下载结果</li>
            </ul>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // 获取DOM元素
            const audioFile = document.getElementById('audioFile');
            const fileName = document.getElementById('fileName');
            const volumeSlider = document.getElementById('volume');
            const speedSlider = document.getElementById('speed');
            const volumeValue = document.getElementById('volumeValue');
            const speedValue = document.getElementById('speedValue');
            const audioPreview = document.getElementById('audioPreview');
            const processBtn = document.getElementById('processBtn');
            const downloadBtn = document.getElementById('downloadBtn');
            const processingIndicator = document.getElementById('processingIndicator');
            const progressBar = document.getElementById('progressBar');

            // 音频处理相关变量
            let originalAudioBuffer = null;
            let audioContext = null;
            let processedAudioURL = null;

            // 更新音量显示值
            volumeSlider.addEventListener('input', function() {
                volumeValue.textContent = this.value;
                if (audioPreview.src && !processedAudioURL) {
                    audioPreview.volume = this.value / 100;
                }
            });

            // 更新速度显示值
            speedSlider.addEventListener('input', function() {
                speedValue.textContent = parseFloat(this.value).toFixed(1);
                if (audioPreview.src && !processedAudioURL) {
                    audioPreview.playbackRate = parseFloat(this.value);
                }
            });

            // 文件选择处理
            audioFile.addEventListener('change', function(e) {
                const file = e.target.files[0];
                if (file) {
                    fileName.textContent = file.name;
                    const fileURL = URL.createObjectURL(file);
                    audioPreview.src = fileURL;
                    audioPreview.volume = volumeSlider.value / 100;
                    audioPreview.playbackRate = parseFloat(speedSlider.value);
                    downloadBtn.style.display = 'none';
                    // 重置处理状态
                    if (processedAudioURL) {
                        URL.revokeObjectURL(processedAudioURL);
                        processedAudioURL = null;
                    }
                } else {
                    fileName.textContent = '未选择文件';
                }
            });

            // 处理音频按钮
            processBtn.addEventListener('click', function() {
                if (!audioPreview.src) {
                    alert('请先选择音频文件！');
                    return;
                }

                processAudio();
            });

            // 下载按钮
            downloadBtn.addEventListener('click', function() {
                if (!processedAudioURL) {
                    alert('没有可下载的音频！');
                    return;
                }
                
                const a = document.createElement('a');
                a.href = processedAudioURL;
                a.download = 'processed_audio.wav';
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
            });

            // 音频处理函数
            async function processAudio() {
                if (!audioFile.files.length) return;

                // 显示处理指示器
                processingIndicator.style.display = 'block';
                processBtn.classList.add('disabled');
                processBtn.textContent = '处理中...';
                progressBar.style.width = '0%';

                try {
                    const file = audioFile.files[0];
                    const arrayBuffer = await file.arrayBuffer();
                    
                    // 创建AudioContext
                    audioContext = new (window.AudioContext || window.webkitAudioContext)();
                    
                    // 解码音频数据
                    updateProgress(20, '解码音频...');
                    originalAudioBuffer = await audioContext.decodeAudioData(arrayBuffer);
                    
                    // 应用音量调整
                    updateProgress(40, '调整音量...');
                    const volume = parseInt(volumeSlider.value) / 100;
                    const volumeAdjustedBuffer = adjustVolume(originalAudioBuffer, volume);
                    
                    // 应用速度调整
                    updateProgress(70, '调整速度...');
                    const speed = parseFloat(speedSlider.value);
                    const speedAdjustedBuffer = adjustSpeed(volumeAdjustedBuffer, speed);
                    
                    // 转换为WAV格式
                    updateProgress(90, '生成音频文件...');
                    const wavBlob = audioBufferToWav(speedAdjustedBuffer);
                    processedAudioURL = URL.createObjectURL(wavBlob);
                    
                    // 更新预览
                    updateProgress(100, '完成!');
                    audioPreview.src = processedAudioURL;
                    downloadBtn.style.display = 'block';
                    
                    setTimeout(() => {
                        processingIndicator.style.display = 'none';
                        processBtn.classList.remove('disabled');
                        processBtn.textContent = '处理音频';
                    }, 1000);
                    
                } catch (error) {
                    console.error('音频处理出错:', error);
                    alert('音频处理失败: ' + error.message);
                    processingIndicator.style.display = 'none';
                    processBtn.classList.remove('disabled');
                    processBtn.textContent = '处理音频';
                }
            }

            // 更新进度显示
            function updateProgress(percent, message) {
                progressBar.style.width = percent + '%';
            }

            // 调整音量
            function adjustVolume(audioBuffer, volume) {
                // 创建新的AudioBuffer
                const newBuffer = audioContext.createBuffer(
                    audioBuffer.numberOfChannels,
                    audioBuffer.length,
                    audioBuffer.sampleRate
                );

                // 处理每个声道
                for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
                    const originalData = audioBuffer.getChannelData(channel);
                    const newData = newBuffer.getChannelData(channel);
                    
                    // 应用音量调整
                    for (let i = 0; i < originalData.length; i++) {
                        newData[i] = originalData[i] * volume;
                    }
                }
                
                return newBuffer;
            }

            // 调整速度（使用重采样）
            function adjustSpeed(audioBuffer, speed) {
                // 计算新的长度
                const newLength = Math.round(audioBuffer.length / speed);
                const newBuffer = audioContext.createBuffer(
                    audioBuffer.numberOfChannels,
                    newLength,
                    audioBuffer.sampleRate
                );

                // 处理每个声道
                for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
                    const originalData = audioBuffer.getChannelData(channel);
                    const newData = newBuffer.getChannelData(channel);
                    
                    // 重采样
                    for (let i = 0; i < newLength; i++) {
                        const originalIndex = i * speed;
                        const index1 = Math.floor(originalIndex);
                        const index2 = Math.min(index1 + 1, originalData.length - 1);
                        const fraction = originalIndex - index1;
                        
                        // 线性插值
                        newData[i] = originalData[index1] + fraction * (originalData[index2] - originalData[index1]);
                    }
                }
                
                return newBuffer;
            }

            // 将AudioBuffer转换为WAV格式
            function audioBufferToWav(buffer) {
                const length = buffer.length;
                const numberOfChannels = buffer.numberOfChannels;
                const sampleRate = buffer.sampleRate;
                const arrayBuffer = new ArrayBuffer(44 + length * numberOfChannels * 2);
                const view = new DataView(arrayBuffer);

                // WAV文件头
                const writeString = (offset, string) => {
                    for (let i = 0; i < string.length; i++) {
                        view.setUint8(offset + i, string.charCodeAt(i));
                    }
                };

                writeString(0, 'RIFF');
                view.setUint32(4, 36 + length * numberOfChannels * 2, true);
                writeString(8, 'WAVE');
                writeString(12, 'fmt ');
                view.setUint32(16, 16, true);
                view.setUint16(20, 1, true);
                view.setUint16(22, numberOfChannels, true);
                view.setUint32(24, sampleRate, true);
                view.setUint32(28, sampleRate * numberOfChannels * 2, true);
                view.setUint16(32, numberOfChannels * 2, true);
                view.setUint16(34, 16, true);
                writeString(36, 'data');
                view.setUint32(40, length * numberOfChannels * 2, true);

                // 写入音频数据
                let offset = 44;
                for (let i = 0; i < length; i++) {
                    for (let channel = 0; channel < numberOfChannels; channel++) {
                        const sample = Math.max(-1, Math.min(1, buffer.getChannelData(channel)[i]));
                        const int16 = sample < 0 ? sample * 0x8000 : sample * 0x7FFF;
                        view.setInt16(offset, int16, true);
                        offset += 2;
                    }
                }

                return new Blob([view], { type: 'audio/wav' });
            }
        });
    </script>
</body>
</html>